package my.algorithms;

import java.lang.reflect.Field;

public class HashCalculater
{
    public static int computeHashKeyFromObject(Object object)
    {
        int result = 17;
        Class<? extends Object> theObject = object.getClass();
        
        //get the field objects using reflection, not this is all fields not 
        // just public fields
        Field[] fields = theObject.getDeclaredFields();

        for (int i = 0, n = fields.length; i < n; i++)
        {
            try
            {
                //only look at fields prefixed with 'f'
                if (fields[i].getName().charAt(0) != 'f')
                {
                    continue;
                }
                
                // Security will stop us if we don't turn this on 
                fields[i].setAccessible(true);
                
                // get the actual object value
                Object value = fields[i].get(object);

                // is it a primative type we can calculate the value of
                if (value == null)
                {
                    result += 0;
                    continue;
                }
                
                if (value instanceof Boolean)
                {
                    result = 37 * result + computeBoolean((Boolean) value);
                    continue;
                }

                if (value instanceof Integer || value instanceof Character
                        || value instanceof Short)
                {
                    result = 37 * result + (Integer) value;
                    continue;
                }
                
                if (value instanceof Byte)
                {
                    result = 37 * result + (int)((Byte)value);
                    continue;
                }

                if (value instanceof Long)
                {
                    result = 37 * result + computeLong((Long) value);
                    continue;
                }
                
                if (value instanceof Float)
                {
                    result = 37 * result + Float.floatToIntBits((Float)value);
                    continue;
                }
                
                if (value instanceof Double)
                {
                    result = 37 * result + computeLong(Double.doubleToLongBits((Double)value));
                    continue;
                }
                
                if (value instanceof String)
                {                    
                    result = 37 * result + computeString((String)value);
                    continue;
                }
                
                //complex types call their hash code on
                result = 37 * result + value.hashCode();
            }  
            catch (IllegalAccessException e)
            {
                System.out.println(e);
            }
        }

        return result;
    }

    private static int computeBoolean(boolean value)
    {
        return value ? 0 : 1;
    }

    private static int computeLong(long value)
    {
        return (int) (value ^ (value >>> 32));
    }
    
    private static int computeString(String value)
    {
        /*int result = 17;
        byte [] bytes = value.getBytes();
        for (int i = 0, n = bytes.length; i < n; i++)
        {
            result = 37 * result + (int)bytes[i];
        }*/
        return value.hashCode();
    }
}
